/* boris*/
#include "libBigNum.h"

big_number big_number:: SQRT()
{
	big_number temp=*this,result,accur,num_5;
	int stop_count=20;
	unsigned long help=temp._num_array[0];
	unsigned short old_precision ,accur_up;
	if(!temp._sign)
	{
		throw BNException(INVALID_OPPERATION_ERR);
	}
	else
	{
		temp._num_array[0]=(unsigned long)sqrt(help);           //  calculation initial value for interaction Newton-Raphson method
		if(temp._arr_size-temp._fractionalPart>1)                  
			temp._arr_size= (temp._arr_size-temp._fractionalPart)/2+temp._fractionalPart;
	
		accur_up=(*this)._arr_size-(*this)._fractionalPart+precision;	      
		free(accur._num_array);
		accur._num_array=(unsigned long*)calloc(precision+1,sizeof(unsigned long)); 
		accur._num_array[precision]=1;
		accur._arr_size=precision+1;
		accur._fractionalPart=precision; //0.0000...01 (num of zeroes after dot= ACCURANCE)
		accur._sign=true;                //needed known 'positive' for absolute value comparison
		result=temp;                      //result- x(n+1);  temp- x(n)
		old_precision=precision;
		do
		{
			setDivisionPrecision(old_precision);
			if(result._fractionalPart>3*precision)
			{
				result._arr_size=result._arr_size-result._fractionalPart+3*precision;
				result._fractionalPart=3*precision;
			}
			temp=result;
			old_precision=precision;
			setDivisionPrecision(3*precision);
			result=(*this)/(temp*2)+(temp*0.5);  //Newton-Raphson method's formula for square root
			stop_count--;
		} while(stop_count&&ABS(result-temp)>accur);

		setDivisionPrecision(old_precision);
		free(num_5._num_array);						//for rounding step
		num_5._num_array=(unsigned long*)calloc((precision+2),sizeof(unsigned long));
		num_5._num_array[precision+1]=500000000;
		num_5._arr_size=precision+2;
		num_5._fractionalPart=precision+1; //0.0000...01 (num of zeroes after dot= ACCURANCE)
		num_5._sign=true;                //needed known 'positive' for absolute value comparison

		result+=num_5;
		if(result._fractionalPart>precision)
		{
			result._arr_size=result._arr_size-result._fractionalPart+precision;
			result._fractionalPart=precision;
		}
		return result;
	}

}